/*
Basic example of the utilization of JSBase to create a custom class
-------------------------------------------------------------------

function myClass(argsObj) {
	this.init(argsObj);
};

myClass.prototype = new JSBase();
myClass.prototype.constructor = myClass;

myClass.members = {
	memberOne: {
		check: [
			utilities.nullFilter,
			utilities.isFunction
		],
		defaultValue: function() {
			alert('hola');
		}
	},
	memberTwo: {
		check: [
			{
				twoSubmemberOne: [
					utilities.nullFilter,
					utilities.isString
				],
				twoSubmemberTwo: [
					{
						twoSubmemberTwoOne: [
							utilities.nullFilter,
							utilities.isString
						],
						twoSubmemberTwoTwo: [
							utilities.nullFilter,
							utilities.isNumber
						]
					}
				]
			}
		],
		defaultValue: {
			twoSubmemberOne: 'defaultTwoSubmemberOne',
			twoSubmemberTwo: {
				twoSubmemberTwoOne: 'defaultTwoSubmemberTwoOne',
				twoSubmemberTwoTwo: 0
			}
		}
	},
	memberThree: {
		check: [
			{
				threeSubmemberOne: [
					utilities.nullFilter,
					utilities.isString
				],
				threeSubmemberTwo: [
					{
						threeSubmemberTwoOne: [
							utilities.nullFilter,
							utilities.isString
						],
						threeSubmemberTwoTwo: [
							utilities.nullFilter,
							utilities.isNumber
						]
					}
				]
			}
		],
		defaultValue: {
			threeSubmemberOne: 'defaultThreeSubmemberOne',
			threeSubmemberTwo: {
				threeSubmemberTwoOne: 'defaultThreeSubmemberTwoOne',
				threeSubmemberTwoTwo: 0
			}
		}
	},
	
	memberFour: {
		check: [
		],
		defaultValue: 'defaultMemberFour',
		getter: {
			fn: function() {
				return this.memberFour;
			},
			name: 'getMemberFour'
		},
		setter: {
			fn: function(value) {
				var result = this.checkMemberSet({
					name: 'memberFour'
					value: value
				});
				if (result.returnedTrue.length == 1)
					this.memberFour = value;
				else 
					throw new TypeError();
			}
			name: 'setMemberFour'
		}
	}
};
-------------------------------------------------------------------
*/

function JSBase(argsObj) {
};

// Static Members

// invoke it with call/apply
JSBase.getObjectPath = function(path) {
	var currentObj = this;
	var pathIte = 0;
	do {
		currentObj = currentObj[path[pathIte]];
		pathIte++;
	} while(
		(typeof(currentObj) != 'undefined') &&
		(pathIte < path.length)
	);
	return currentObj;
};
	
// invoke it with call/apply	
JSBase.setObjectPath = function(argsObj) {
	// 	argsObj: (object)
	//		- path: (array) submembers name in order
	//		- value: the value it will be setted in the last level
	var currentObj = this;
	var currentMemberName;
	var pathIte = 0;
	while(
		(typeof(currentObj) != 'undefined') &&
		(pathIte < argsObj.path.length - 1)
	) {
		currentMemberName = argsObj.path[pathIte];
		if (!(currentMemberName in currentObj)) {
			currentObj[currentMemberName] = {};
		};
		currentObj = currentObj[currentMemberName];
		pathIte++;
	};
	currentObj[argsObj.path[pathIte]] = argsObj.value;
};

// Public Members

JSBase.prototype.checkMemberSet = function(argsObj) {
	// 	argsObj: (object)
	//		- name: (string) member name
	//		-	value: the value that want to check if it can be setted
	
	// var initialitation
	var self = this;
	var checkIte = 0;
	var currentMember = ('current' in argsObj)?
		argsObj.current :
		{
			check: (argsObj.name in self.constructor.members)?
				self.constructor.members[argsObj.name].check :
				void(0),
			path: [argsObj.name],
			value: argsObj.value
		};
	var result = {
		returnedFalse: [],
		returnedTrue: [],
		returnedUndefined: []
	};
	var submember = {};
	var submemberName;
	var submemberResult = {
		returnedFalse: [],
		returnedTrue: [],
		returnedUndefined: []
	};
	var subcheckIte;
	var subResult;
	// var initialitation [end]
	if ((currentMember.check) && (currentMember.check.length > 0)) {
		do {
			switch (typeof(currentMember.check[checkIte])) {
				case 'function':
					switch(currentMember.check[checkIte](currentMember.value)) {
						case false:
							result.returnedFalse.push(currentMember.path.slice());
							break;
						case void(0):
							result.returnedUndefined.push(currentMember.path.slice());
							break;
					};
					break;
				case 'object':
					if (currentMember.check[checkIte] instanceof Array) {
						subResult = (currentMember.check[checkIte].length > 0) ?
							false :
							true;
						subcheckIte = 0;
						while (
							(!subResult) &&
							(subcheckIte < currentMember.check[checkIte].length)
						) {
							if (currentMember.check[checkIte][subcheckIte](currentMember.value) == true) {
								subResult = true;
							};
							subcheckIte++;
						};
						if (!subResult)
							result.returnedFalse.push(currentMember.path.slice());
					}
					else { // pure Object
						if (typeof(currentMember.value) == 'object') {
							for (submemberName in currentMember.check[checkIte]) {
								submember.check = currentMember.check[checkIte][submemberName];
								submember.path = currentMember.path.slice();
								submember.path.push(submemberName);
								submember.value = (
									(typeof(currentMember.value) != 'undefined') && 
									(currentMember.value != null) && 
									(submemberName in currentMember.value)
								)?
									currentMember.value[submemberName] :
									void(0);
								submemberResult = this.checkMemberSet({
									current: submember,
									name: argsObj.name,
									value: argsObj.value
								});
								for (var resultIte = 0; resultIte < submemberResult.returnedFalse.length; resultIte++) {
									result.returnedFalse.push(submemberResult.returnedFalse[resultIte].slice());
								};
								for (var resultIte = 0; resultIte < submemberResult.returnedTrue.length; resultIte++) {
									result.returnedTrue.push(submemberResult.returnedTrue[resultIte].slice());
								};
								for (var resultIte = 0; resultIte < submemberResult.returnedUndefined.length; resultIte++) {
									result.returnedUndefined.push(submemberResult.returnedUndefined[resultIte].slice());
								};
							};
						}
						else {
							result.returnedFalse.push(currentMember.path.slice());
						};
					};
					break;
			};
			checkIte++;
		} while(
			(result.returnedFalse.length == 0) &&
			(result.returnedUndefined.length == 0) &&
			(checkIte < currentMember.check.length)
		);
		if ((result.returnedFalse.length == 0) &&
				(result.returnedUndefined.length == 0) &&
				(result.returnedTrue.length == 0)) {
			result.returnedTrue.push(currentMember.path.slice());
		};
	};
	return result;
};

JSBase.prototype.init = function(argsObj) {
	var memberDefault;
	var memberName;
	var members = argsObj;
	for (memberName in this.constructor.members) {
		memberDefault = this.constructor.members[memberName];
		if ((memberDefault.getter != null) && 
				(memberDefault.getter instanceof Object) &&
				('name' in memberDefault.getter)){
			this[memberDefault.getter.name] = memberDefault.getter.fn;
		};
		if ((memberDefault.setter != null) && 
				(memberDefault.setter instanceof Object) &&
				('name' in memberDefault.setter)){
			this[memberDefault.setter.name] = memberDefault.setter.fn;
		};
		if (!(memberName in argsObj)) {
			members[memberName] = void(0);
		};
	};
	this.setMembers(members, true, true);
};

JSBase.prototype.setMembers = function(members, callSetter, setDefault) {
	var currentResult;
	var memberDefault;
	var memberName;
	var result = {
		returnedFalse: [],
		returnedUndefined: [],
		returnedTrue: []
	};
	var resultIte;
	var self = this;
	var value;
	
	// iteration over the members passed in members
	for (memberName in members) {
		if ((callSetter) && 
				('setter' in self.constructor.members[memberName])) {
			self.constructor.members[memberName].setter.fn.call(self, members[memberName]);
		}
		else {
			currentResult = self.checkMemberSet({
				name: memberName,
				value: members[memberName]
			});
			for (resultIte = 0; resultIte < currentResult.returnedFalse.length; resultIte++) {
				result.returnedFalse.push(currentResult.returnedFalse[resultIte].slice());
			};
			for (resultIte = 0; resultIte < currentResult.returnedTrue.length; resultIte++) {
				result.returnedTrue.push(currentResult.returnedTrue[resultIte].slice());
			};
			for (resultIte = 0; resultIte < currentResult.returnedUndefined.length; resultIte++) {
				result.returnedUndefined.push(currentResult.returnedUndefined[resultIte].slice());
			};
		};
	};
	console.dir(result);
	if (result.returnedFalse.length == 0) {
		if (setDefault) {
			for (resultIte = 0; resultIte < result.returnedUndefined.length; resultIte++) {
				memberName = result.returnedUndefined[resultIte][0];
				if (result.returnedUndefined[resultIte].length == 0) {
					value = self.constructor.members[memberName].defaultValue;
				}
				else {
					memberDefault = {};
					memberDefault[memberName] = self.constructor.members[memberName].defaultValue;
					value = JSBase.getObjectPath.call(memberDefault, result.returnedUndefined[resultIte]);
				};
				JSBase.setObjectPath.call(self, {
					path: result.returnedUndefined[resultIte],
					value: value
				});
			};
		};
		for (resultIte = 0; resultIte < result.returnedTrue.length; resultIte++) {
			memberName = result.returnedTrue[resultIte][0];
			if (result.returnedTrue[resultIte].length == 0) {
				value = members[memberName];
			}
			else {
				value = JSBase.getObjectPath.call(members, result.returnedTrue[resultIte]);
			};
			JSBase.setObjectPath.call(self, {
				path: result.returnedTrue[resultIte],
				value: value
			});
		};
	};
	return result;
};
